/*
 * @file test_creationclass.cpp
 */

/*****************************************************************************
**  $Id: test_creationclass.cpp 8865 2008-02-04 18:54:02Z andrew $
**
**  This is part of the dxflib library
**  Copyright (C) 2001 Andrew Mustun
**
**  This program is free software; you can redistribute it and/or modify
**  it under the terms of the GNU Library General Public License as
**  published by the Free Software Foundation.
**
**  This program is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU Library General Public License for more details.
**
**  You should have received a copy of the GNU Library General Public License
**  along with this program; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
******************************************************************************/

#include "EntityCreation.h"
#include "DxfLayer.h"
#include "PointEntity.h"
#include "LineEntity.h"
#include "SolidEntity.h"
#include "PolylineEntity.h"
#include "CircleEntity.h"
#include "ArcEntity.h"
#include "TextEntity.h"
#include "dl_codes.h"

#include <QColor>
#include <iostream>
#include <stdio.h>

using namespace TGS::GeoMath;

namespace
{
	QColor numberToColor24(int num) {
		return QColor(
			(num&0x00ff0000) >> 16,
			(num&0x0000ff00) >> 8,
			(num&0x000000ff) >> 0
			);
	}

	QColor numberToColor(int num, const double dxfColors[][3], 
						 bool comp = false, bool forLayer = false)
	{
		if (forLayer) {
			num = abs(num);
		}

		// Compatibility with QCad 1.5.3 and older:
		if (comp) {
			switch(num) {
			case 0:
				return QColor(Qt::black);
				break;
			case 1:
				return QColor(Qt::darkBlue);
				break;
			case 2:
				return QColor(Qt::darkGreen);
				break;
			case 3:
				return QColor(Qt::darkCyan);
				break;
			case 4:
				return QColor(Qt::darkRed);
				break;
			case 5:
				return QColor(Qt::darkMagenta);
				break;
			case 6:
				return QColor(Qt::darkYellow);
				break;
			case 7:
				return QColor(Qt::lightGray);
				break;
			case 8:
				return QColor(Qt::darkGray);
				break;
			case 9:
				return QColor(Qt::blue);
				break;
			case 10:
				return QColor(Qt::green);
				break;
			case 11:
				return QColor(Qt::cyan);
				break;
			case 12:
				return QColor(Qt::red);
				break;
			case 13:
				return QColor(Qt::magenta);
				break;
			case 14:
				return QColor(Qt::yellow);
				break;
			case 15:
				return QColor(Qt::black);
				break;
			default:
				break;
			}
		} else {
			if (num==0) {
				return QColor(/*RColor::ByBlock*/);
			} else if (num==256) {
				return QColor(/*RColor::ByLayer*/);
			} else if (num<=255 && num>=0) {
				return QColor((int)(dxfColors[num][0]*255),
					(int)(dxfColors[num][1]*255),
					(int)(dxfColors[num][2]*255));
			} else {
				return QColor(/*RColor::ByLayer*/);
			}
		}
		return QColor();
	}

	QColor attributesToColor(int color, int color24, 
							const double dxfColors[][3], bool forLayer) 
	{
		QColor ret;
		if (color24!=-1) {
			ret = numberToColor24(color24);
		}
		else {
			ret = numberToColor(color, dxfColors, false, forLayer);
		}

		return ret;
	}
}

/**
 * Default constructor.
 */
EntityCreation::EntityCreation() 
	: _dxfRenderModel(new DxfRenderModel())
	, _tempPolylineEntity(nullptr)
	, _polylineClosed(false)
{
	_modelSpaceBlock.origin = Point(0, 0);
	_modelSpaceBlock.name = "*Model_Space";
	_dxfBlocks[_modelSpaceBlock.name] = _modelSpaceBlock;

	_currentBlock = _modelSpaceBlock;
}


/**
 * Sample implementation of the method which handles layers.
 */
void EntityCreation::addLayer(const DL_LayerData& data) {

	DxfLayer layer;
	layer.setLayerName(data.name.c_str());
	QColor color = attributesToColor(attributes.getColor(), attributes.getColor24(), 
					dxfColors, true);
	if(QColor(Qt::white) == color ) color = Qt::black;
	layer.setColor(color);

	_dxfRenderModel->addLayer(layer);
}

/**
 * Sample implementation of the method which handles point entities.
 */
void EntityCreation::addPoint(const DL_PointData& data) 
{
	PointEntity* entity = new PointEntity();
	entity->setPoint(PointEntity::Point(data.x, data.y));
	addEntity(entity);
}

/**
 * Sample implementation of the method which handles line entities.
 */
void EntityCreation::addLine(const DL_LineData& data)
{
  	LineEntity* entity = new LineEntity();
	entity->setLinePoints(Point(data.x1, data.y1), Point(data.x2, data.y2));
	addEntity(entity);
}

/**
 * Sample implementation of the method which handles arc entities.
 */
void EntityCreation::addArc(const DL_ArcData& data) 
{
	ArcEntity* arcEntity = new ArcEntity();
	arcEntity->setArc(Point(data.cx, data.cy), data.radius, data.angle1, data.angle2);
	addEntity(arcEntity);
}

/**
 * Sample implementation of the method which handles circle entities.
 */
void EntityCreation::addCircle(const DL_CircleData& data) 
{
	CircleEntity* entity = new CircleEntity();
	entity->setCircle(Point(data.cx, data.cy), data.radius);
	addEntity(entity);
}


/**
 * Sample implementation of the method which handles polyline entities.
 */
void EntityCreation::addPolyline(const DL_PolylineData& data) 
{
	_polylineClosed = data.flags & 0x1;
	_tempPolylineEntity = new PolylineEntity();
	addEntity(_tempPolylineEntity);
}


/**
 * Sample implementation of the method which handles vertices.
 */
void EntityCreation::addVertex(const DL_VertexData& data) 
{   
	_tempPolylineEntity->addPoint(data.x, data.y);
}


void EntityCreation::add3dFace(const DL_3dFaceData& data) {
    printf("3DFACE\n");
    for (int i=0; i<4; i++) {
        printf("   corner %d: %6.3f %6.3f %6.3f\n", 
            i, data.x[i], data.y[i], data.z[i]);
    }
    printAttributes();
}


void EntityCreation::printAttributes() {
    printf("  Attributes: Layer: %s, ", attributes.getLayer().c_str());
    printf(" Color: ");
    if (attributes.getColor()==256)	{
        printf("BYLAYER");
    } else if (attributes.getColor()==0) {
        printf("BYBLOCK");
    } else {
        printf("%d", attributes.getColor());
    }
    printf(" Width: ");
    if (attributes.getWidth()==-1) {
        printf("BYLAYER");
    } else if (attributes.getWidth()==-2) {
        printf("BYBLOCK");
    } else if (attributes.getWidth()==-3) {
        printf("DEFAULT");
    } else {
        printf("%d", attributes.getWidth());
    }
    printf(" Type: %s\n", attributes.getLineType().c_str());
}

void EntityCreation::endEntity()
{
	if(_tempPolylineEntity)
	{
		if(_polylineClosed)
		{
			Point point = _tempPolylineEntity->getPolyline().getPoint(0);
			_tempPolylineEntity->addPoint(point);
		}

		_tempPolylineEntity = nullptr;
	}

	
}

void EntityCreation::addEntity( DxfEntity* entity )
{
	entity->setLayerName(attributes.getLayer().c_str());
	entity->setBlockName(_currentBlock.name);
	_dxfRenderModel->addEntity(entity->getLayerName(), entity);
	_entities.push_back(entity);

	// Color:
	QColor col = numberToColor(attributes.getColor(), dxfColors);
	QColor col24 = numberToColor24(attributes.getColor24());

	if(attributes.getColor() == 256 || attributes.getColor() == 0)
	{
		entity->setColor(_dxfRenderModel->getLayerColor(entity->getLayerName()));
	}
	else
	{
		QColor color; 
		if (attributes.getColor24()!=-1) 
		{
			color = col24;
		}
		else 
		{
			color = col;
		}

		if(QColor(Qt::white) == color ) color = Qt::black;
		entity->setColor(color);		
	}
}

void EntityCreation::addSolid( const DL_SolidData& data )
{
	Point v1(data.x[0], data.y[0]);
	Point v2(data.x[1], data.y[1]);
	Point v3(data.x[2], data.y[2]);
	Point v4(data.x[3], data.y[3]);

	SolidEntity* entity = new SolidEntity();
	entity->addPoint(v1);
	entity->addPoint(v2);
	entity->addPoint(v4);
	entity->addPoint(v3);

	addEntity(entity);

}

void EntityCreation::addBlock( const DL_BlockData& data )
{
	_currentBlock.name = data.name.c_str();
	_currentBlock.origin = Point(data.bpx, data.bpy);
	_dxfBlocks[_currentBlock.name] = _currentBlock;
}

void EntityCreation::endBlock()
{
	_currentBlock = _modelSpaceBlock;
}

void EntityCreation::addInsert( const DL_InsertData& data )
{
	BlockReferenceData referData;
	referData.name = data.name.c_str();
	referData.position = Point(data.ipx, data.ipy);
	_blockReferenceDatas[referData.name] = referData;
}

void EntityCreation::recalculateEntityCoord()
{
	for (size_t i = 0; i < _entities.size(); ++i)
	{
		DxfBlock& block = _dxfBlocks[_entities[i]->getBlockName()];
		Point origin = block.origin;
		origin.setX(-origin.getX());
		origin.setY(-origin.getY());
		_entities[i]->traslate(origin);

		auto finder = _blockReferenceDatas.find(_entities[i]->getBlockName());
		if(finder != _blockReferenceDatas.end()) 
		{
			_entities[i]->traslate(finder->second.position);
		}
	}
	
}

void EntityCreation::finish()
{
	recalculateEntityCoord();
}

void EntityCreation::addText( const DL_TextData& data )
{
	TextEntity* entity = new TextEntity();
	entity->setText(data.text.c_str(), Point(data.ipx, data.ipy),data.height ,data.angle);
	addEntity(entity);
}










    

// EOF
